/**
 * FileFind - ftp/shares indexing and search php engine
 * Module: persist-jpa20
 * Description: Persistence implementation with JPA 2.0
 * Copyright (c) 2003-2010 Rage Steel, www.gt2.ru
 */
package ru.ffind.persist.jpa20.service;

import static ru.ffind.persist.jpa20.model.QueryNames.FIND_DIRS_BY_PARENT;
import static ru.ffind.persist.jpa20.model.QueryNames.FIND_DIR_BY_NAME;
import static ru.ffind.persist.jpa20.model.QueryNames.FIND_FILES_BY_PARENT;
import static ru.ffind.persist.jpa20.model.QueryNames.PARAM_NAME;
import static ru.ffind.persist.jpa20.model.QueryNames.PARAM_PARENT;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;

import ru.ffind.common.model.Directory;
import ru.ffind.common.model.Entry;
import ru.ffind.common.model.Host;
import ru.ffind.common.model.HostPath;
import ru.ffind.persist.jpa20.model.DirImpl;
import ru.ffind.persist.jpa20.model.FileImpl;
import ru.ffind.persist.jpa20.model.HostImpl;
import ru.ffind.persist.service.EntryService;

/**
 * Entry service.
 *
 * @author Rage Steel
 */
public class EntryServiceImpl extends AbstractServiceImpl
        implements EntryService {

    /**
     * {@inheritDoc}
     */
    @Override
    public List<Entry> findEntries(Directory directory) {
        if (!(directory instanceof DirImpl)) {
            throw new IllegalArgumentException(
                    "directory is not instance of DirImpl!");
        }
        DirImpl dirImpl = (DirImpl) directory;


        EntityManager entityManager = createEntityManager();
        try {
        	return fillEntries(dirImpl, entityManager);
        } finally {
            entityManager.close();
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public List<Entry> findEntriesByHostPath(Host host, HostPath hostPath) {
    	if (!(host instanceof HostImpl)) {
    		throw new IllegalArgumentException("host is not an instance of HostImpl!");
    	}
		Integer parentDirId = host.getRootDirId();
		if (null == parentDirId) {
			// Maybe we need to throw some exception
			return Collections.emptyList();
		}
    	
    	EntityManager entityManager = createEntityManager();
    	try {
    		// Currently it is not clear how to deal with all these possible exceptions
    		DirImpl parentDir = entityManager.getReference(DirImpl.class, parentDirId);
    		for (String dirName : hostPath.getPathItems()) {
    			TypedQuery<DirImpl> subDirQuery = entityManager.createNamedQuery(FIND_DIR_BY_NAME, DirImpl.class);
    			subDirQuery.setParameter(PARAM_PARENT, parentDir);
    			subDirQuery.setParameter(PARAM_NAME, dirName);
    			parentDir = subDirQuery.getSingleResult();
    		}
    		return fillEntries(parentDir, entityManager);
    	} finally {
    		entityManager.close();
    	}
    }
    
    @Override
    public List<Entry> findEntriesById(Integer dirId) {
    	EntityManager entityManager = createEntityManager();
    	Directory dir = entityManager.find(DirImpl.class, dirId);
    	return findEntries(dir);
    }
    
	private List<Entry> fillEntries(DirImpl dirImpl, EntityManager entityManager) {
		List<Entry> result = new ArrayList<Entry>();
		findEntries(FIND_DIRS_BY_PARENT, DirImpl.class,
				entityManager, result, dirImpl);
		
		findEntries(FIND_FILES_BY_PARENT, FileImpl.class,
				entityManager, result, dirImpl);

		return result;
	}
    
    private <T extends Entry> void findEntries(String queryName, Class<T> entryClass,
    	// Criteria is better than JPQL, but first i need to know it better!
    	// So just JPQL
		EntityManager entityManager, List<Entry> result, DirImpl parent) {
    	TypedQuery<T> entryQuery = entityManager.createNamedQuery(queryName, entryClass);
    	entryQuery.setParameter(PARAM_PARENT, parent);
    	result.addAll(entryQuery.getResultList());
    }

}
